SQL Server 2008 hosts the common language runtime
(CLR), implementing what’s known as the Hosting API. The Hosting API
gives SQL Server 2008 full control over the execution of .NET code in a
carefully managed environment that honors the shared resource usage of
both SQL Server and the CLR. The CLR provides an execution context far
safer than that of code you might formerly have run in an extended
stored procedure or COM object under SQL Server 2000 and previous
editions.
In the sections that
follow, you will create one of each of the managed versions of database
routines and types. You work with both the SQL Server project type in
Visual Studio 2008 as well as the T-SQL Data Definition Language (DDL)
syntax for managed objects.
Finally, you’ll learn about advanced topics such as transaction control in mixed (T-SQL and managed) environments.
An Introduction to Custom Managed Database Objects
The capability to run
managed code presents a world of possibilities, yet these features must
be leveraged appropriately. The meaning of appropriate
will ultimately be the result of ongoing dialogs between database
administrators and the developers who want to use the .NET Framework in
SQL Server.
Just like SQL Server’s capability to host web services , this feature set begins to blur the line
between SQL Server as a database server and SQL Server as a lightweight
application server.
.NET assemblies are built
using Visual Studio or the command-line compilers and then literally
uploaded into the database and loaded into memory on the same physical
server as the SQL Server instance. CLR objects may therefore consume
valuable server and network resources.
This scenario presents a
challenging new management paradigm that database administrators,
managers, and developers have to negotiate. Administrators are just
beginning to consider strategies for what kinds of .NET code they should
allow to run and in which contexts. Following are a few general rules
to consider regarding when managed objects should and should not be
used:
Data selection
and modification should always be performed using T-SQL because that’s
what it’s optimized to do. You should not create a T-SQL wrapper in your
.NET code.
You
should use managed code when you need to overcome the procedural
limitations of T-SQL, such as avoiding the use of nested cursors that
connect to multiple databases and other awkward constructs. (SQL was
never developed to be a procedural language, only a set-based query
language.)
You
should use managed code when you want to extend the per-row or per-set
effects of routines to leverage managed resources, such as XML parsers,
web services, and custom code libraries.
The software development
staff still must decide what to do, but we can be thankful that SQL
Server has some rules of its own for what kinds of operations can be
called and under which permission sets, as discussed in the following
section.
Managed Object Permissions
The
first thing to know about managed object permissions is that SQL Server
has only blessed a certain group of assemblies usable under each of the
three SQL Server permission sets.
Figure 1
shows the Add References dialog for a SQL Server project in Visual
Studio 2008, listing these .NET Framework assemblies. They are the only
assemblies (aside from user-created assemblies) that can be referenced
in SQL Server projects. Note that this list doesn’t change in Visual
Studio, regardless of the permission set used. Note also that SQL Server
and/or Visual Studio walks down the reference chain to see whether any
referenced assemblies reference anything that is not blessed. Therefore,
you shouldn’t bother trying to get around this list; there isn’t even a
Browse button on the dialog box as there is with the other project
types.
The Three Permission Sets
SQL Server has three built-in
.NET Code Access Security (CAS) permission sets that define which kinds
of operations can be executed at runtime. Using the CAS layer is a huge
improvement over running extended stored procedures under default login
credentials because it allows for fine-grained permission granting and
revocation.
These are the permission sets, in increasing order of freedom:
SAFE
EXTERNAL_ACCESS
UNSAFE
These keywords are used in the DDL syntax for assemblies.
Assuming
that you have built an assembly targeted for SQL Server use (which you
do in the next section), you can use the following syntax for loading
that assembly into your database of choice:
CREATE ASSEMBLY AssemblyName [AUTHORIZATION LoginName]
FROM StringPathToAssemblyDll | BinaryDataValue
[WITH PERMISSION_SET (SAFE | EXTERNAL_ACCESS | UNSAFE) ]
This syntax is reasonably
self-explanatory: you tell SQL Server the name of the assembly and the
path (using a UNC if needed) to it. If you’re loading an assembly from a
varbinary column, you supply the
actual data that makes up the compiled code of the assembly instead of
the path to it (Visual Studio does this).
Note
CREATE ASSEMBLY and ALTER ASSEMBLY are commands used by Visual Studio’s Deploy feature, which does the managed code DDL work for you.
The WITH PERMISSION SET clause is optional, and it defaults to SAFE. Marking an assembly with the SAFE
permission set indicates that no external resources (for example, the
Registry, web services, file I/O) are going to be accessed. The DDL will
fail if assemblies such as System.IO
are referenced, and anything causing a permission demand for executing
similar operations will result in an exception being thrown at runtime.
Marking an assembly with the EXTERNAL_ACCESS permission set tells SQL Server that it will be using resources such as networking, files, and so forth. Assemblies such as System.Web.Services (but not System.Web) may be referenced with this set.
Marking an assembly with the UNSAFE
permission set tells SQL Server that not only might external resources
be used, but unmanaged code may even be invoked from managed code.
Some assemblies in the
.NET Framework go so far as to tell the processes that ultimately host
them (such as SQL Server or Internet Explorer) about their relative
safety, using a specific .NET attribute: HostProtectionAttribute (HPA).
The enumeration flags of the
HPA’s parameter indicate to the host what kinds of operations the
classes decorated with it may attempt. Because documentation of the HPA
with regards to SQL Server is scant, it’s unclear whether SQL Server
ultimately relies on the HPA to determine what may be loaded. (It seems
to do so at runtime, but the blessed list is likely to be hard coded.)
Following are some of the operations you cannot perform with .NET code running under SQL Server’s SAFE and EXTERNAL_ACCESS options (but possibly under UNSAFE):
Thread synchronization
External process management
Framework security changes
Use of non-read-only static fields
Only those in the sysadmin role can upload UNSAFE assemblies to SQL Server. (Just don’t tell your DBA we told you how to do it.)
The EXTERNAL_ACCESS permission on master is required for uploading EXTERNAL_ACCESS assemblies. And anyone in the db_owner role may load SAFE assemblies.
Developing Managed Objects with Visual Studio 2008
When SQL Server 2008 is installed, it includes Microsoft.SqlServer.Server,
the assembly that contains the attributes and other classes needed for
SQLCLR (the common acronym for managed code running in SQL Server)
programming.
The first step in working with SQLCLR is to enable the feature in SQL Server.
Setting Up the Server for Managed Code Execution
Before you can work with managed database objects, you need to execute the following T-SQL commands in the context of the master database:
sp_configure 'clr enabled', 1
RECONFIGURE
go
This step is necessary because SQL Server comes with managed code execution turned off by default.
At this point, you’re
ready to create your first SQLCLR project using Visual Studio 2008 (VS).
Start VS and create a new C#-based SQL Server project with a name of
your choosing (the example is named SQL2008SQLCLR). Figure 2 shows the Add New Project dialog.
Next,
VS asks you to create or add a reference to a database to which you
will deploy your new assembly. During deployment, your assembly (and
with it, all its SQLCLR types and routines) is uploaded directly into
SQL Server’s system tables. Select AdventureWorks2008 so you can work with the examples that follow.
Next, you create your first managed SQL Server object, a stored procedure written in C#.